package cn.tedu.mall.front.service.impl;

import cn.tedu.mall.common.exception.CoolSharkServiceException;
import cn.tedu.mall.common.restful.ResponseCode;
import cn.tedu.mall.front.service.IFrontCategoryService;
import cn.tedu.mall.pojo.front.entity.FrontCategoryEntity;
import cn.tedu.mall.pojo.front.vo.FrontCategoryTreeVO;
import cn.tedu.mall.pojo.product.vo.CategoryStandardVO;
import cn.tedu.mall.product.service.front.IForFrontCategoryService;
import lombok.extern.slf4j.Slf4j;
import org.apache.dubbo.config.annotation.DubboReference;
import org.apache.dubbo.config.annotation.DubboService;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;

@DubboService
@Service
@Slf4j
public class FrontCategoryServiceImpl implements IFrontCategoryService {
    //Redis的key，我们定义成常量
    public static final String CATEGORY_TREE_KEY="category_tree";
    @Autowired
    private RedisTemplate redisTemplate;
    //从数据库中查询分类信息，通过远程调用实现的
    @DubboReference
    private IForFrontCategoryService dubboCategoryService;

    @Override
    public FrontCategoryTreeVO categoryTree() {
        //1.先检查Redis中是否包含分类信息的三级树
        //判断Redis中是否包含CATEGORY_TREE_KEY
        if(redisTemplate.hasKey(CATEGORY_TREE_KEY)){
            //redis中已经包含该信息，直接返回
            FrontCategoryTreeVO<FrontCategoryEntity> treeVo =
                    (FrontCategoryTreeVO<FrontCategoryEntity>) redisTemplate.boundValueOps(CATEGORY_TREE_KEY).get();
            return treeVo;
        }
        //代码走到这里，说明Redis中没有数据
        //2.从数据库中查询出来
        List<CategoryStandardVO> categoryStandardVOS = dubboCategoryService.getCategoryList();
        //3.构建三级树
        FrontCategoryTreeVO<FrontCategoryEntity> treeVO = initTree(categoryStandardVOS);
        //4.保存到redis中
        redisTemplate.boundValueOps(CATEGORY_TREE_KEY).set(treeVO,30, TimeUnit.DAYS);
        //返回
        return treeVO;
    }

    private FrontCategoryTreeVO<FrontCategoryEntity> initTree(List<CategoryStandardVO> categoryStandardVOS) {
        //第一部分：确定所有分类对象的父分类
        //parent_id-->子id  声明一个Map，使用父分类id做key，使用子分类对象集合做这个Map的value
        //将所有有相同父分类id的对象添加到对应的集合中
        Map<Long,List<FrontCategoryEntity>> map = new HashMap<>();
        log.info("当前分类对象的总和为:{}",categoryStandardVOS.size());
        //遍历categoryStandardVOS
        for (CategoryStandardVO categoryStandardVO : categoryStandardVOS) {
            //categoryStandardVO对象没有子分类的属性，需要将他转成FrontCategoryEntity
            FrontCategoryEntity frontCategoryEntity = new FrontCategoryEntity();
            //利用BeanUtils进行同名属性赋值
            BeanUtils.copyProperties(categoryStandardVO,frontCategoryEntity);
            //根据父分类id做map的key值
            Long parentId = frontCategoryEntity.getParentId();
            //根据当前分类对象的父分类id向map中添加元素，但是要先判断是否已经在map中存在该key
            if(map.containsKey(parentId)){
                //如果有这个key，直接将当前的对象保存到list中
                map.get(parentId).add(frontCategoryEntity);
            } else {
                //如果没有这个key，我们不仅需要创建key还需要创建对应的value--List
                List<FrontCategoryEntity> value = new ArrayList<>();
                value.add(frontCategoryEntity);
                //使用当前parentId作为key，List类型的value当作value值
                map.put(parentId,value);
            }
        }
        //第二部分：将子分类对象关联到父分类包含的children属性中
        //从map中的根分类开始，通过循环遍历每个级别的分类对象，添加到对应级别的children属性中
        //一级分类，父Id是0L
        List<FrontCategoryEntity> firstLevels = map.get(0L);
        //判断firstLevels是否为空
        if(firstLevels==null)
            throw new CoolSharkServiceException(ResponseCode.INTERNAL_SERVER_ERROR,"当前项目没有根分类");
        //遍历一级分类集合
        for (FrontCategoryEntity firstLevel : firstLevels) {
            //获得一级分类的id，一级分类id是二级分类的父id
            Long secondLevelParentId = firstLevel.getId();
            //获取二级分类的集合
            List<FrontCategoryEntity> secondLevels = map.get(secondLevelParentId);
            //判断二级分类集合是否为空
            if(secondLevels==null){
                log.warn("当前分类缺少二级分类对象,{}",firstLevel);
                //结束本次循环
                continue;
            }
            //遍历二级集合
            for (FrontCategoryEntity secondLevel : secondLevels) {
                //二级集合的id是三级分类的父id
                Long thirdLevelParentId = secondLevel.getId();
                //获取三级分类的集合
                List<FrontCategoryEntity> thirdLevels = map.get(thirdLevelParentId);
                //判断三级集合是否为空
                if(thirdLevels==null){
                    log.warn("当前分类缺少三级分类对象,{}",secondLevel);
                    continue;
                }
                //讲三级集合添加到二级分类对象的children属性中
                secondLevel.setChildrens(thirdLevels);
            }
            //将二级集合添加到一级分类对象的children属性中
            firstLevel.setChildrens(secondLevels);
        }
        //到处为止，所有分类对象的父子关系已经构建完成
        //转成FrontCategoryTreeVO<FrontCategoryEntity>对象进行返回
        FrontCategoryTreeVO<FrontCategoryEntity> treeVO = new FrontCategoryTreeVO<>();
        //将一级分类集合添加到该对象的属性中
        treeVO.setCategories(firstLevels);
        return treeVO;
    }
}
